<template>
    <div class='label-tree-container'>
        <a-button type="primary" class='add-first' @click='addFirst'>添加一级分类</a-button>
        <div class='table-title'>
            <div class='name'>标签名称</div>
            <div class='sort'>排序</div>
            <div class='status'>开启状态</div>
            <div class='opera'>操作</div>
        </div>
        <div class='table-body'>
            <a-tree
                v-if='treeData.length'
                :tree-data="treeData"
                :replace-fields='replaceFields'
                :expanded-keys="expandedKeys"
                :defaultExpandAll='true'
                :key='key'
                @expand="onExpand"
            >
                <template slot="custom" slot-scope="item">
                    <div class='custom-node'>
                        <div class='name'>
                            <a-input :ref="item.type || ''" v-model='item.name' @blur='changeName(item.name, item)' />
                        </div>
                        <div class='sort'>
                            <a-input-number
                                v-if="item.type !== 'newInput'"
                                v-model='item.sort'
                                :formatter="value => `${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')"
                                :parser="value => value.replace(/\$\s?|(,*)/g, '')"
                                @blur='changeSort(item.sort, item)'
                            />
                        </div>
                        <div class='status'>
                            停用<a-switch :disabled='!!item.type' v-model='item.status' @change='changeSwitch($event, item)' />启用
                        </div>
                        <div class='opera'>
                            <a-button type="primary" v-if='item.tier < 2' @click='addNode(item)'>添加子节点</a-button>
                            <a-button type="danger" @click='deleteNode(item)'>删除节点</a-button>
                        </div>
                    </div>
                </template>
            </a-tree>
            <a-empty v-else />
        </div>
    </div>
</template>

<script>
export default {
    name: 'LabelTreeQuality',
    data () {
        return {
            treeData: [],
            replaceFields: {
                children: 'children',
                title: 'name',
                key: 'id'
            },
            expandedKeys: [],
            key: 0
        }
    },
    created () {
        this.getTree()
    },
    methods: {
        async getTree () {
            const res = await this.$ApiServer['operationConfig/getTree/quality']()
            if (res.code === 200) {
                const add = (list) => {
                    list.forEach((item) => {
                        item.scopedSlots = { title: 'custom' }
                        if (item.children && item.children.length) {
                            item.children = add(item.children)
                        } else {
                            item.children = []
                        }
                        item.sort = item.sort || 0
                        item.status = !!item.status
                    })
                    return list
                }
                this.treeData = add(res.data)
            } else {
                this.$message.error(res.message)
            }
        },
        onExpand (expandedKeys) {
            this.expandedKeys = expandedKeys
        },
        addFirst () {
            this.treeData.push({
                name: '',
                id: new Date().getTime(),
                tier: 1,
                scopedSlots: {
                    title: 'custom'
                },
                status: false,
                type: 'newInput',
                parentId: '1',
                children: [],
                sort: 0
            })
            this.$nextTick(() => {
                this.$refs.newInput.focus()
            })
        },
        async changeName (name, data) {
            const isNew = data.type === 'newInput'
            if (!name.match(/^[ ]*$/)) {
                let status = data.status
                if (status) {
                    status = data.tier === 1 ? !!data.children.filter(item => item.status).length : data.status
                }
                const res = await this.$ApiServer['operationConfig/updateNode/quality']({
                    id: isNew ? '' : data.id,
                    name: data.name,
                    parentId: data.parentId,
                    status: status ? 1 : 0,
                    tier: data.tier,
                    sort: data.sort || 0
                })
                if (res.code === 200) {
                    this.getTree()
                    this.$message.success(isNew ? '添加成功' : '编辑成功')
                } else {
                    if (isNew) this.toDelete(data)
                    this.$message.error(res.message)
                }
            } else if (isNew) {
                this.toDelete(data)
            }
        },
        async changeSort (sort, data) {
            if (sort) {
                const res = await this.$ApiServer['operationConfig/updateNode/quality']({
                    id: data.id,
                    name: data.name,
                    parentId: data.parentId,
                    tier: data.tier,
                    sort
                })
                if (res.code === 200) {
                    this.getTree()
                    this.$message.success('排序成功')
                } else {
                    sort = ''
                    this.$message.error(res.message)
                }
            }
        },
        /**
         * 二级关闭时，判断同级是否有打开的，并关闭所有三级
         *     有： 一级不关闭
         *     无： 关闭一级
         * 关闭一级时，关闭下面所有
         * -------------------------------
         * 打开二级 有无子级
         *     有：打开二级和所有子级
         *     无，不处理
         * 打开一级 有无二级
         *     有: 打开二级，按照上面的判断
         *          是否有二级打开
         *              有： 打开一级
         *              无： 不处理
         *     无：不处理
         * @param check 启用状态
         * @param data  节点
         * @param type  是否是删除后调用, delete
         */
        async changeSwitch (check, data, type) {
            const isDelete = type === 'delete'
            if (!isDelete) {
                data.dataRef.status = check
            }
            const ids = []
            // 打开
            if (check) {
                if (data.tier === 2) {
                    ids.push(data.id)
                    const oneNode = this.getNode(data.parentId)
                    ids.push(oneNode.id)
                } else if (data.children.length) {
                    // 打开一级
                    ids.push(data.id)
                    // 添加二级的id
                    ids.push(...data.children.map(item => item.id))
                } else {
                    data.dataRef.status = !check
                }
            } else {
                // 关闭
                if (!isDelete) {
                    ids.push(data.id)
                }
                if (data.children && !isDelete) {
                    // 关闭所有子级
                    ids.push(...this.getAllChildId(data.id))
                }
                if (data.tier === 2) {
                    const oneNode = this.getNode(data.parentId)
                    const oneChild = oneNode.children
                    // 二级同级是否有打开的
                    if (!oneChild.filter(item => item.status).length) {
                        // 无  关闭一级
                        ids.push(data.parentId)
                    }
                }
            }
            if (ids.length) {
                const res = await this.$ApiServer['operationConfig/changeStatus/quality']({
                    ids,
                    status: check ? 1 : 0
                })
                if (res.code === 200) {
                    this.getTree()
                    this.$message.success(res.message)
                } else {
                    this.getTree()
                    this.$message.error(res.message)
                }
            }
        },
        addNode (data) {
            data.dataRef.children.push({
                name: '',
                id: new Date().getTime(),
                tier: data.tier + 1,
                scopedSlots: {
                    title: 'custom'
                },
                status: false,
                type: 'newInput',
                parentId: data.id,
                children: []
            })
            if (!this.expandedKeys.includes(data.id)) {
                this.expandedKeys.push(data.id)
            }
            this.$nextTick(() => {
                this.$refs.newInput.focus()
            })
        },
        deleteNode (data) {
            this.$confirm({
                title: '提示',
                content: '确认是否删除分类[' + data.name + ']',
                okText: '确认',
                cancelText: '取消',
                onOk: async () => {
                    const { id } = data
                    const res = await this.$ApiServer['operationConfig/deleteNode/quality']({
                        id
                    })
                    if (res.code === 200) {
                        await this.getTree()
                        this.changeSwitch(false, data, 'delete')
                        this.$message.success(res.message)
                    } else {
                        this.$message.error(res.message)
                    }
                },
                onCancel () {}
            })
        },
        toDelete (data) {
            const { parentId, id } = data
            if (parentId !== '1') {
                let node = {}
                const findNode = (list) => {
                    list.forEach((item) => {
                        if (item.id === parentId) {
                            node = item
                        } else if (item.children) {
                            findNode(item.children)
                        }
                    })
                }
                findNode(this.treeData)
                const index = node.children.findIndex(item => item.id === id)
                if (index !== -1) {
                    node.children.splice(index, 1)
                }
            } else {
                const index = this.treeData.findIndex(item => item.id === id)
                if (index !== -1) {
                    this.treeData.splice(index, 1)
                }
            }
        },
        getNode (id) {
            const findNode = (list) => {
                let res = null
                list.forEach((item) => {
                    if (item.id === id) {
                        res = item
                    } else if (item.children) {
                        if (findNode(item.children)) {
                            res = findNode(item.children)
                        }
                    }
                })
                return res
            }
            return findNode(this.treeData)
        },
        getAllChildId (id) {
            const node = this.getNode(id)
            const findId = (list) => {
                const ids = []
                list.forEach((item) => {
                    ids.push(item.id)
                    if (item.children) {
                        ids.push(...findId(item.children))
                    }
                })
                return ids
            }
            return findId(node.children)
        }
    }
}
</script>

<style scoped lang='less'>
.label-tree-container {
    .add-first {
        margin-bottom: 32px;
    }
    .table-title {
        display: flex;
        justify-content: flex-start;
        align-items: center;
        border: 1px solid #ececec;
        font-size: 16px;
        color: #333;
        .name {
            width: calc(100% - 550px);
            padding-left: 16px;
            line-height: 38px;
        }
        .sort {
            width: 110px;
            text-align: center;
            line-height: 38px;
            border-left: 1px solid #ececec;
        }
        .status {
            width: 200px;
            border: 1px solid #ececec;
            border-top: 0;
            border-bottom: 0;
            line-height: 38px;
            text-align: center;
        }
        .opera {
            width: 240px;
            line-height: 38px;
            text-align: center;
        }
    }
    .table-body {
        ::v-deep {
            .ant-tree-switcher {
                margin-top: 4px;
            }
            .ant-tree-node-content-wrapper {
                width: calc(100% - 24px);
                height: 32px;
                display: inline-flex;
                align-items: center;
                .ant-tree-title {
                    width: 100%;
                }
            }
            .ant-empty {
                margin-top: 40px;
            }
        }
        .custom-node {
            display: flex;
            justify-content: flex-start;
            align-items: center;
            .name {
                width: calc(100% - 550px);
            }
            .sort {
                width: 100px;
                margin-left: 10px;
            }
            .status {
                width: 200px;
                text-align: center;
                font-size: 16px;
                color: #333;
                button {
                    margin: 0 4px;
                }
                ::v-deep {
                    .ant-switch-checked.ant-switch-loading .ant-switch-loading-icon {
                        color: #3DB572;
                    }
                    .ant-switch:focus {
                        outline: 0;
                        box-shadow: 0 0 0 2px rgba(61, 181, 114, 0.2);
                    }
                    .ant-switch-checked {
                        background-color: #3DB572;
                    }
                }
            }
            .opera {
                width: 240px;
                text-align: right;
            }
        }
    }
    ::v-deep {
        .ant-input-number-handler-wrap {
            display: none;
        }
    }
}
</style>
